package com.study.aoki.reactive.endpoint

import com.study.aoki.reactive.auth.InvalidTokenException
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler
import org.springframework.http.HttpStatus
import org.springframework.http.codec.HttpMessageWriter
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.HandlerStrategies
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.result.view.ViewResolver
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono

/**
 * @author jiahan.zhou
 * @date 2021/7/5
 */
@Component
class GlobalErrorHandler : ErrorWebExceptionHandler {

    override fun handle(exchange: ServerWebExchange, ex: Throwable): Mono<Void> = handle(ex)
            .flatMap {
                it.writeTo(exchange, HandlerStrategiesResponseContext(HandlerStrategies.withDefaults()))
            }
            .flatMap {
                Mono.empty()
            }

    fun handle(throwable: Throwable): Mono<ServerResponse> {
        return when (throwable) {
            is InvalidTokenException -> createResponse(HttpStatus.UNAUTHORIZED, "401", "登录已失效")
            else -> createResponse(HttpStatus.INTERNAL_SERVER_ERROR, "500", "未知异常")
        }
    }

    fun createResponse(httpStatus: HttpStatus, code: String, message: String): Mono<ServerResponse> =
            ServerResponse.status(httpStatus).bodyValue(mapOf("code" to code, "message" to message))


    private class HandlerStrategiesResponseContext(val strategies: HandlerStrategies) : ServerResponse.Context {

        override fun messageWriters(): List<HttpMessageWriter<*>> {
            return this.strategies.messageWriters()
        }

        override fun viewResolvers(): List<ViewResolver> {
            return this.strategies.viewResolvers()
        }
    }
}